﻿using System;
using System.Diagnostics;
using System.IO.Ports;
using System.Windows;
using System.Windows.Controls;
using Serial;

namespace AMSRemote
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public enum State
        {
            Ready,
            WaitCommandAck,
            WaitDataAck
        }

        private State state;
        private string typeString;
        private string dataString;
        private bool dataRecieve;

        private SerialPort mySerialPort;
        public MainWindow()
        {
            InitializeComponent();
            mySerialPort = new SerialPort();
        }

        private void ButtonConnect_Click(object sender, RoutedEventArgs e)
        {
            
            if(!mySerialPort.IsOpen && ComboboxComport.SelectedIndex != -1)
            {
                mySerialPort = new SerialPort(ComboboxComport.SelectedItem.ToString(), 19200, Parity.None, 8, StopBits.One);


                mySerialPort.DataReceived += DataReceivedHandler;
                mySerialPort.Handshake = Handshake.None;
                mySerialPort.NewLine = "stop";
                mySerialPort.ReadTimeout = 250;

                try
                {
                    mySerialPort.Open();
                    ButtonConnect.Content = "Disconnect";
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Comport is busy, please select another.");
                }
                
            }
            else
            {
                try
                {
                    mySerialPort.Close();
                    ButtonConnect.Content = "Connect";
                    mySerialPort = new SerialPort();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed when trying to close");
                }
            }
        }
        
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            string indata = "";
            
            try
            {
                indata += mySerialPort.ReadLine();
            }
            catch (TimeoutException)
            {
            }
            
            Debug.WriteLine("indata: " + indata);

            if (indata.Length == 0)
            {
                Debug.WriteLine("indata arraysize is 0! aka BAD");
                SendData("A", "NACK");
                return;
            }

            char type = indata[0];
            if (type != 'D' && type != 'C' && type != 'A' && type != 'L')
            {
                Debug.WriteLine("Fail startbit");
                SendData("A", "NACK");
                mySerialPort.DiscardInBuffer();
                return;
            }
           
            string sizestr = indata.Substring(1, 1);
            sizestr = ConvertToHex(sizestr);

            int size;
            if(!int.TryParse(sizestr, out size))
            {
                Debug.WriteLine("Size was wack");
                SendData("A", "NACK");
            }

            string text = indata.Substring(0, size + 2);

            //if ack
            if(text.Substring(2, size) == "ACK")
            {
                Debug.WriteLine("Recieved ACK");
                
                if(dataRecieve)
                {
                    state = State.WaitDataAck;
                }
                else
                {
                    state = state = State.Ready;
                }
                return;
            }

            //if nack
            if (text.Substring(2, size) == "NACK")
            {
                Debug.WriteLine("Recieved NACK, Resending");
                SendData(typeString, dataString);
                return;
            }

            Debug.WriteLine("Checksum1: " + chck(text));
            Debug.WriteLine("Checksum2: " + indata.Substring(2 + size, 1));
            bool ack = false;

            if (chck(text) != char.Parse(indata.Substring(2 + size, 1)))
            {
                SendData("A", "NACK");
                return;
            }

            SendData("A", "ACK");
            
            text = indata.Substring(2, size);
            Debug.WriteLine("Type: " + indata[0]);
            Debug.WriteLine("Recieved text: " + text);

            RecieveData(indata[0].ToString(), text);
        }

        public void RecieveData(string type, string data)
        {
            Debug.WriteLine("Recived type:" + type);
            Debug.WriteLine("Recieved command: " + data);

            state = State.Ready;

            switch (type)
            {
                case "L":
                    MessageBox.Show("Light recieved: " + data);
                    break;
                case "C":
                    MessageBox.Show("Command Recieved: " + data);
                    break;
            }
        }

        public bool CheckSumVerify(string data, char chksum)
        {
            char datachk = chck(data);
            Debug.WriteLine("Check1: " + ConvertToHex(datachk.ToString()) + " Check2: " + ConvertToHex(chksum.ToString()));
            return datachk == chksum;
        }

        public string ConvertToHex(string asciiString)
        {
            string hex = "";
            foreach (char c in asciiString)
            {
                int tmp = c;
                hex += String.Format("{0:x2}", (uint)Convert.ToUInt32(tmp.ToString()));
            }
            return hex;
        }

        public char chck(string data)
        {
            int retval = 0;

            for (int i = 0; i < data.Length; i++)
            {
                retval ^= data[i];
            }
            return (char)retval;
        }
        
        private void SendData(string type, string text)
        {
            typeString = type;
            dataString = text;
            char str = (char)text.Length;

            string dataToSend = type + str + text;

            dataToSend += chck(dataToSend);

            mySerialPort.Write(dataToSend);
            Debug.WriteLine("Sending: " + dataToSend);
        }

        private void ButtonUp_Click(object sender, RoutedEventArgs e)
        {
            int speed = (int)SliderSpeed.Value;
            SendData("C", "SpeeF" + (char)speed);
            state = State.WaitCommandAck;
            dataRecieve = false;
        }

        private void ButtonLeftClick(object sender, RoutedEventArgs e)
        {
            int speed = (int)SliderSpeed.Value;
            SendData("C", "SpeeL" + (char)speed);
            state = State.WaitCommandAck;
            dataRecieve = false;
        }

        private void ButtonReadLight_Click(object sender, RoutedEventArgs e)
        {
            SendData("D", "Ligh");
            state = State.WaitCommandAck;
            dataRecieve = true;
        }

        private void ButtonReadTemp_Click(object sender, RoutedEventArgs e)
        {
            SendData("D", "Temp");
            state = State.WaitCommandAck;
            dataRecieve = true;
        }

        private void ButtonRight_Click(object sender, RoutedEventArgs e)
        {
            int speed = (int)SliderSpeed.Value;
            SendData("C", "SpeeR" + (char)speed);
            state = State.WaitCommandAck;
            dataRecieve = false;
        }

        private void ButtonDown_Click(object sender, RoutedEventArgs e)
        {
            int speed = (int)SliderSpeed.Value;
            SendData("C", "SpeeB" + (char)speed);
            state = State.WaitCommandAck;
            dataRecieve = false;
        }

        private void ButtonStop_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("Sending: Stop");
            SendData("C", "SpeeF" + (char)0);
            state = State.WaitCommandAck;
            dataRecieve = false;
        }
    }
}


namespace Serial
{
    public class Port
    {
        public String[] Ports
        {
            get
            {
                return SerialPort.GetPortNames();
            }
        }

    }

    public class Data : EventArgs
    {
        public Data(bool value)
        {
            Recieved = value;
        }

        public bool Recieved
        {
            get;
            set;
        }
    }

}